package com.xcc.core.lock;

import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.I0Itec.zkclient.IZkDataListener;
import org.I0Itec.zkclient.ZkClient;
//import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xcc.core.LockEmnu;
import com.xcc.core.util.ZkClientUitl;



/**
 * 读锁 顺序读后面+写判断
 * <简述>
 * <详细描述>
 * @author   xcc
 * @version  $Id$
 * @since
 * @see
 */
public class ZKRWLock implements RWLock{


    private static final Logger LOG=LoggerFactory.getLogger(ZKRWLock.class);

    private static final String LOCK_NODE_PARENT_PATH = "/share_lock";

    private ZkClient zkClient=ZkClientUitl.getClient();
    static {
        ZkClientUitl.createEphemeralSerino(LOCK_NODE_PARENT_PATH+"read-", "".getBytes());
    }
    public  ReadLocK mReadLocK=new ReadLocK();
    public  WriteLocK mWriteLocK = new WriteLocK();



    @Override
    public ReadLocK readLock() {
        return  mReadLocK;
    }

    @Override
    public Lock writeLock() {
        return mWriteLocK;
    }

    //读锁共享锁
    class ReadLocK extends ZKAbstractLock{
        LockEmnu mLockRead=LockEmnu.failed;
        
        String pathName;
        public ReadLocK() {
            pathName=ZkClientUitl.createEphemeralSerino(LOCK_NODE_PARENT_PATH+"/read-","".getBytes());
        }

        /**
         * @see 排序是否是第一位
         */
        @Override
        public boolean lock()  throws Exception {
            List<String> paths=  zkClient.getChildren(LOCK_NODE_PARENT_PATH);
            paths.sort(nameComparator);
            //读锁直接获取
            if(isFirstNode(pathName,paths)||mLockRead==LockEmnu.success) {
                return true;
            }else {
                return false;
            }
        }

        @Override
        public boolean unlock() {
            try {
                zkClient.delete(pathName);
                return true;
            } catch (Exception e) {
                LOG.error(e.getMessage(), e);
            }
            return false;
        }


        @Override
        public void waitLock() throws Exception {
            CountDownLatch countDownLatch = new CountDownLatch(1);
            List<String> path=zkClient.getChildren(LOCK_NODE_PARENT_PATH);
            path.sort(nameComparator);
            //监听器
            IZkDataListener iZkDataListener = new IZkDataListener() {
                //节点被删除回调
                @Override
                public void handleDataDeleted(String dataPath) throws Exception {
                    if (countDownLatch != null) {
                        countDownLatch.countDown();
                    }
                }
                //节点改变被回调
                @Override
                public void handleDataChange(String dataPath, Object data) throws Exception {
                }
            };
            String listenPath=LOCK_NODE_PARENT_PATH+"/"+path.get(path.indexOf(pathName.substring(pathName.lastIndexOf("/")+1))-1);
            System.out.println("监听："+listenPath);
            if(zkClient.exists(listenPath)&&!canAcquireLock(pathName.replaceAll(LOCK_NODE_PARENT_PATH+"/", ""),path)) {
                zkClient.subscribeDataChanges(listenPath, iZkDataListener);
               countDownLatch.await();
            }else {
                mLockRead=LockEmnu.success;
            }
        }

    }
    //写锁排他锁
    class WriteLocK implements Lock{

        @Override
        public boolean lock()
            throws Exception {
            return false;
        }

        @Override
        public boolean unlock() {
            return false;
        }

    }
   // @Test
    static int ii=0;
    public static void main(String[]  args) throws Exception {
  //  public void test() {
   
        for (int i=0;i<100;i++) { 
            Thread thread = new Thread(()-> {
                ZKRWLock zkLock = new ZKRWLock();
                try { 
                    zkLock.readLock().getLock();
                    System.out.println("读表"+ii++);
                    zkLock.readLock().unlock();
                } catch (Exception e1) {
                    e1.printStackTrace(); } });
            thread.start(); 
        }

    }



}



